package com.kcht.itsed.mws.alefacade.stdfacade.impl;

import com.kcht.itsed.mws.alefacade.exceptions.*;
import com.kcht.itsed.mws.alefacade.stdfacade.ALELR;
import com.kcht.itsed.mws.aleframework.intf.IActiveSpecScheduler;
import com.kcht.itsed.mws.aleframework.intf.ILogicalReaderContainer;
import com.kcht.itsed.mws.alemodel.LRProperty;
import com.kcht.itsed.mws.alemodel.LRSpec;
import com.kcht.itsed.mws.extendmodel.jpa.LogicReaderEntity;
import com.kcht.itsed.mws.persist.dao.ILogicReaderDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Optional;

@Component
public class ALELR_IMPL implements ALELR{

	@Autowired
	private ILogicReaderDao lrDao;
	@Autowired ILogicalReaderContainer logicalReaderContainer;
	@Autowired IActiveSpecScheduler activeSpecScheduler;
	
	@Override
	public void define(String name, LRSpec spec) throws DuplicateNameException, ValidationException {
		Optional<LogicReaderEntity> existedEntity = lrDao.findBySpecName(name);
		if(existedEntity.isPresent())throw new DuplicateNameException("LR spec ["+name+"] already existed.");
		//TODO 校验规则
		
		LogicReaderEntity lrEntity = new LogicReaderEntity();
		lrEntity.setLrName(name);
		lrEntity.setLrSpec(spec);
		lrDao.insert(lrEntity);
		logicalReaderContainer.updateLRSpec(name,spec);
	}

	@Override
	public void update(String name, LRSpec spec) throws NoSuchNameException, ValidationException, InUseException,
			ImmutableReaderException, ReaderLoopException {
		Optional<LogicReaderEntity> existedEntity = lrDao.findBySpecName(name);
		existedEntity.orElseThrow(()->new NoSuchNameException("No such LR spec ["+name+"]"));
		
		//TODO 校验规则
		//或许不用检查在用，为解决热割接的问题，即使LR在用，也不抛出inuse异常
		
		logicalReaderContainer.updateLRSpec(name, spec);
		
		//如果LR关联的规则有活动EC订阅，那么需要shuffle规则。
		if(logicalReaderContainer.isLrReferencesByActiveSpec(name)) {
			activeSpecScheduler.shuffleSpec();
		}
		
		existedEntity.ifPresent(s->{
			s.setLrSpec(spec);
			lrDao.updateById(s);
		});
		
	}

	@Override
	public void undefine(String name) throws NoSuchNameException, InUseException, ImmutableReaderException {
		Optional<LogicReaderEntity> existedEntity = lrDao.findBySpecName(name);
		existedEntity.orElseThrow(()->new NoSuchNameException("No such LR spec ["+name+"]"));
		
		//TODO 检查在用
		if(logicalReaderContainer.isLrReferencesByActiveSpec(name))
			throw new InUseException("LR ["+name+"] is in use");

		lrDao.deleteById(existedEntity.get());
		logicalReaderContainer.removeLRSpec(name);
	}

	@Override
	public List<String> getLogicalReaderNames() {
		return lrDao.queryLogicReader();
	}

	@Override
	public LRSpec getLRSpec(String name) throws NoSuchNameException {
		Optional<LogicReaderEntity> lro = lrDao.findBySpecName(name);
		lro.orElseThrow(()->new NoSuchNameException("No such LR spec ["+name+"]"));
		return lro.get().getLrSpec();
	}

	@Override
	public void addReaders(String name, List<String> readers) throws NoSuchNameException, ValidationException,
			InUseException, ImmutableReaderException, NonCompositeReaderException, ReaderLoopException {
		//复合逻辑阅读器暂不支持
		throw new ImplementationException("Composited read not supported yet.");
	}

	@Override
	public void setReaders(String name, List<String> readers) throws NoSuchNameException, ValidationException,
			InUseException, ImmutableReaderException, NonCompositeReaderException, ReaderLoopException {
		//复合逻辑阅读器暂不支持
		throw new ImplementationException("Composited read not supported yet.");
	}

	@Override
	public void removeReaders(String name, List<String> readers)
			throws NoSuchNameException, InUseException, ImmutableReaderException, NonCompositeReaderException {
		//复合逻辑阅读器暂不支持
		throw new ImplementationException("Composited read not supported yet.");
	}

	@Override
	public void setProperties(String name, List<LRProperty> properties)
			throws NoSuchNameException, ValidationException, InUseException, ImmutableReaderException {
		//逻辑阅读器关联的物理阅读器及CRAP元组，也使用property关联到LR中。但这部分参数不可设置及调取。
		//可调取的内容只包括阅读器平滑等参数
		Optional<LogicReaderEntity> lro = lrDao.findBySpecName(name);
		lro.orElseThrow(()->new NoSuchNameException("LR name ["+name+"] not existed."));
		
		LogicReaderEntity lr = lro.get();
		List<LRProperty> property = lr.getLrSpec().getProperties().getProperty();
		property.forEach(oldProp->{
			properties.stream().filter(p->p.getName().equals(oldProp.getName()))
				.findFirst().ifPresent(newProperty->
					oldProp.setValue(newProperty.getValue())
				);
		});
		lrDao.updateById(lr);
	}
	
	private void checkSupportedPropertyName(String propertyName) {
		//检查支持的参数名
		if(propertyName.equals("prId") || propertyName.equals("crap"))throw new ImplementationException("Cannot reference to property ["+propertyName+"]");
		//TODO 其他参数名检查
	}

	@Override
	public String getPropertyValue(String name, String propertyName) throws NoSuchNameException {
		checkSupportedPropertyName(propertyName);
		Optional<LogicReaderEntity> lro = lrDao.findBySpecName(name);
		lro.orElseThrow(()->new NoSuchNameException("LR name ["+name+"] not existed."));
		Optional<LRProperty> prop = lro.get().getLrSpec().getProperties().getProperty().stream().filter(lpr->lpr.getName().equals(propertyName)).findFirst();
		prop.orElseThrow(()->new NoSuchNameException("No property name ["+propertyName+"]"));
		return prop.get().getValue();
	}

}
